package piwan.ai;

import java.util.ArrayList;

import piwan.*;
import piwan.GameState.Phase;

public class AIController extends GameState.Controller {

	private boolean usePlayerInfo = false;
	private PlayerInfo[] pinfo;
	private GameState gs = null;
	private ArrayList<Region> myCapitals = new ArrayList<Region>();

	private int nAttacking;
	private int nDefending;
	public boolean combatWindow= true; // more than 12 troops per turn

	public AIController(GameState gs, Player p) {
		gs.super();
		this.gs = gs;
		addControl(p);
		pinfo = new PlayerInfo[gs.getPlayerCount()];
		for (Player pr : gs.getPlayers())
			pinfo[pr.getId()] = new PlayerInfo(pr);
	}

	public void capitalChosen(Region r) {

	}

	public void combatCancelled() {
		
	}

	public void combatRoundEnded(int hidden, int guessed, boolean newRound) {

		if (!newRound && isControlling())
			combatWindow = false;
		// statistics, adaptation (...)
		if (usePlayerInfo) {
			pinfo[gs.getAttacking().getId()]
					.updateTab(nDefending, (nAttacking > gs.getCombatTo()
							.getType().getMaxAttack()) ? gs.getCombatTo()
							.getType().getMaxAttack() : nAttacking, hidden,
							true);

			pinfo[gs.getDefending().getId()]
					.updateTab(nDefending, (nAttacking > gs.getCombatTo()
							.getType().getMaxAttack()) ? gs.getCombatTo()
							.getType().getMaxAttack() : nAttacking, guessed,
							false);
		}

		if (newRound) {
			nAttacking = gs.getCombatFrom().getSoldiers();
			nDefending = gs.getCombatTo().getSoldiers();
			if (isControlling(gs.getAttacking())) {
				if (gs.getCombatFrom().getSoldiers() < 3)
					cancelCombat();
				else if (usePlayerInfo)
					combatAttack(pinfo[gs.getDefending().getId()]
							.combatPlay(false, gs.getCombatTo().getSoldiers(),
									(gs.getCombatFrom().getSoldiers() > gs
											.getCombatTo().getType()
											.getMaxAttack()) ? gs.getCombatTo()
											.getType().getMaxAttack() : gs
											.getCombatFrom().getSoldiers()));
				else
					combatAttack(combatPlay(1, (gs.getCombatFrom()
							.getSoldiers() > gs.getCombatTo().getType()
							.getMaxAttack()) ? gs.getCombatTo().getType()
							.getMaxAttack() : gs.getCombatFrom().getSoldiers()));
			}
			if (isControlling(gs.getDefending())) {
				if (usePlayerInfo)
					combatDefend(pinfo[gs.getAttacking().getId()]
							.combatPlay(true, gs.getCombatTo().getSoldiers(),
									(gs.getCombatFrom().getSoldiers() > gs
											.getCombatTo().getType()
											.getMaxAttack()) ? gs.getCombatTo()
											.getType().getMaxAttack() : gs
											.getCombatFrom().getSoldiers()));
				else
					combatDefend(combatPlay(1, (gs.getCombatFrom()
							.getSoldiers() > gs.getCombatTo().getType()
							.getMaxAttack()) ? gs.getCombatTo().getType()
							.getMaxAttack() : gs.getCombatFrom().getSoldiers()));
			}

		}
	}

	public void phaseChanged(Phase p) {
		if (gs.getPhase() == GameState.Phase.COMBAT) {
			nAttacking = gs.getCombatFrom().getSoldiers();
			nDefending = gs.getCombatTo().getSoldiers();
			// System.out.println("Boris");

			if (isControlling(gs.getAttacking())) {
				if (usePlayerInfo)
					combatAttack(pinfo[gs.getDefending().getId()]
							.combatPlay(false, gs.getCombatTo().getSoldiers(),
									(gs.getCombatFrom().getSoldiers() > gs
											.getCombatTo().getType()
											.getMaxAttack()) ? gs.getCombatTo()
											.getType().getMaxAttack() : gs
											.getCombatFrom().getSoldiers()));
				else
					combatAttack(combatPlay(1, (gs.getCombatFrom()
							.getSoldiers() > gs.getCombatTo().getType()
							.getMaxAttack()) ? gs.getCombatTo().getType()
							.getMaxAttack() : gs.getCombatFrom().getSoldiers()));
			}
			if (isControlling(gs.getDefending())) {
				if (usePlayerInfo)
					combatDefend(pinfo[gs.getAttacking().getId()]
							.combatPlay(true, gs.getCombatTo().getSoldiers(),
									(gs.getCombatFrom().getSoldiers() > gs
											.getCombatTo().getType()
											.getMaxAttack()) ? gs.getCombatTo()
											.getType().getMaxAttack() : gs
											.getCombatFrom().getSoldiers()));
				else
					combatDefend(combatPlay(1, (gs.getCombatFrom()
							.getSoldiers() > gs.getCombatTo().getType()
							.getMaxAttack()) ? gs.getCombatTo().getType()
							.getMaxAttack() : gs.getCombatFrom().getSoldiers()));
			}
			// gs.getGroupManager().

		}
		if (isControlling()) {
			updateMyCapitals();

			if (gs.getPhase() == GameState.Phase.ATTACK && combatWindow) {
				System.out.println("Attack");
				for (Region attacking : gs.getWorld().getRegions()) {
					if (attacking.isOwnedBy(gs.getCurrentPlayer())) {
						for (Region attacked : attacking.getAdjacent()) {
							if (attacking.getSoldiers() > 2
									&& attacked.isOwned()
									&& !attacked.isOwnedBy(gs
											.getCurrentPlayer())) {
								// System.out.println("Begin");
								combatBegin(attacking, attacked);
								return;
							}
						}
					}
				}
				endPhase();
				// if (gs.getPhase() != GameState.Phase.COMBAT)
				// endPhase();
			} else if (gs.getPhase() == GameState.Phase.MOVE) {
				for (Region full : gs.getWorld().getRegions()) {
					if (full.isOwnedBy(gs.getCurrentPlayer())
							&& full.getSoldiers() > 1) {
						// System.out.println("Boris " + (full.getSoldiers() -
						// 2));
						if (full.isCapital() && full.getSoldiers() < 4)
							getSoldiersFrom(full, full.getSoldiers() - 2);
						else
							getSoldiersFrom(full, full.getSoldiers() - 1);
					}
				}
				for (Region capital : myCapitals) {
					for (Region adj : adjRegTo(capital)) {
						if (gs.isRegionControllable(adj) && !adj.isOwned()
								&& adj.getType().hasCombo()) {
							if (gs.getSoldiersLeft() <= 0) {
								endTurn();
								return;
							}
							placeSoldiers(adj, 1);
							if (gs.getSoldiersLeft() <= 0) {
								endTurn();
								return;
							}
						}
					}
				}

				for (int i = 0; i < 3; i++) {
					// System.out.println("Boris2 " + (gs.getSoldiersLeft()));
					for (Region empty : gs.getWorld().getRegions()) {
						if (gs.isRegionControllable(empty) && !empty.isOwned()) {
							if (gs.getSoldiersLeft() <= 0) {
								endTurn();
								return;
							}
							placeSoldiers(empty, 1);
							if (gs.getSoldiersLeft() <= 0) {
								endTurn();
								return;
							}
						}
					}
				}
				for (Region capital : myCapitals) {
					for (Region adj : adjRegTo(capital)) {
						if (gs.isRegionControllable(adj) && !adj.isOwned()) {
							if (gs.getSoldiersLeft() <= 0) {
								endTurn();
								return;
							}
							placeSoldiers(adj, 1);
							if (gs.getSoldiersLeft() <= 0) {
								endTurn();
								return;
							}
						}
					}
				}

				for (Region capital : gs.getWorld().getRegions()) {
					// System.out.println("Boris4 " + (gs.getSoldiersLeft()));
					if (capital.isCapital()
							&& capital.isOwnedBy(gs.getCurrentPlayer())) {
						if (gs.canPlaceSoldiers(capital, gs.getSoldiersLeft())) {
							placeSoldiers(capital, gs.getSoldiersLeft());
							endTurn();
							return;
						}
					}
				}
			}

		}
	}
	public void continueAttacking() {
		combatWindow = true;
		phaseChanged(GameState.Phase.ATTACK);
	}

	public void soldiersPlaced(Region r, int n) {

	}

	public void soldiersRemoved(Region r, int n) {

	}

	public void turnChanged(Player p) {

		if (isControlling()) {
			
			combatWindow = true;

			if (gs.getPhase() == GameState.Phase.CAPITALS) {
				for (Region r : gs.getWorld().getRegions()) {
					if (r.isCapital() && !r.isOwned()) {
						chooseCapital(r);
						return;
					}
				}
			}

			updateMyCapitals();
			
			if (gs.getSoldiersLeft()<=0)
				endTurn();

			if (gs.getPhase() == GameState.Phase.PLACE) {
				for (Region capital : myCapitals) {
					for (Region adj : adjRegTo(capital)) {
						if (adj.isOwned()
								&& !adj.isOwnedBy(gs.getCurrentPlayer())) {
							if (gs.canPlaceSoldiers(capital, gs
									.getSoldiersLeft())) {
								placeSoldiers(capital, gs.getSoldiersLeft());
								endPhase();
								return;
							}
						}
					}
				}
				for (Region myRegion : gs.getWorld().getRegions()) {
					if (myRegion.isOwnedBy(gs.getCurrentPlayer())) {
						for (Region adj : adjRegTo(myRegion)) {
							if (adj.isOwned()
									&& !adj.isOwnedBy(gs.getCurrentPlayer())) {
								if (gs.canPlaceSoldiers(myRegion, gs
										.getSoldiersLeft())) {
									if (gs.getSoldiersLeft() < 6
											|| adj.getSoldiers() > 5) {
										placeSoldiers(myRegion, gs
												.getSoldiersLeft());
										endPhase();
										return;
									} else
										placeSoldiers(myRegion, 6);
								}
							}
						}
					}
				}
				for (Region capital : myCapitals) {
					if (gs.canPlaceSoldiers(capital, gs.getSoldiersLeft())) {
						placeSoldiers(capital, gs.getSoldiersLeft());
						endPhase();
						return;
					}
				}
			}

			/*
			 * for (Region r : gs.getWorld().getRegions()) {
			 * r.isOwnedBy(gs.getCurrentPlayer()); }
			 */
		}
	}

	private void updateMyCapitals() {
		for (Region capital : gs.getWorld().getRegions()) {
			if (capital.isCapital() && capital.isOwnedBy(gs.getCurrentPlayer()))
				myCapitals.add(capital);
		}
	}

	private ArrayList<Region> adjRegTo(Region r) {
		ArrayList<Region> regs = new ArrayList<Region>();
		for (Region adj : gs.getWorld().getRegions())
			if (r.isAdjacentTo(adj))
				regs.add(adj);
		return regs;
	}

	private void regionsInRange(GroupManager.Group g, int n) {
		// gs.getGroupManager().getGroups(pl)
	}

	static private int combatPlay(int from, int to) {
		double[] tab = createBestProbabilities(from, to);
		double a = Math.random();
		double sum = 0;
		for (int i = 0; i < tab.length; i++) {
			sum += tab[i];
			if (a < sum) {
				return from + i;
			}
		}
		return to;
	}

	static private double[] createBestProbabilities(int from, int to) {
		double[] tab = new double[to + 1 - from];

		double ptotal = 0;
		for (int i = from; i <= to; i++) {
			ptotal += 2 / (double) (i + 1);
		}

		for (int i = from; i <= to; i++) {
			tab[i - from] = 2 / (double) (i + 1) / ptotal;
		}

		return (tab);
	}

	@Override
	public void playerEliminated(Player p) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void playerWon(Player p) {
		// TODO Auto-generated method stub
		
	}
}
